package com.authine.cloudpivot.ext.applicationservice;

import com.alibaba.cola.dto.MultiResponse;
import com.alibaba.cola.dto.RequestContext;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.cola.exception.Assert;
import com.alibaba.cola.exception.BizException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.ext.conf.ApplicationConf;
import com.authine.cloudpivot.ext.domain.dto.*;
import com.authine.cloudpivot.ext.domain.vo.MallGoodPageVo;
import com.authine.cloudpivot.ext.domain.vo.MarketGoodsVo;
import com.authine.cloudpivot.ext.domain.vo.OrgVo;
import com.authine.cloudpivot.ext.enums.*;
import com.authine.cloudpivot.ext.model.bosi.BsscResp;
import com.authine.cloudpivot.ext.model.goods.GoodsModel;
import com.authine.cloudpivot.ext.util.*;
import com.authine.cloudpivot.ext.utils.Punchout.PunchoutBosiUtils;
import com.authine.cloudpivot.file.res.AttachmentRes;
import com.authine.cloudpivot.metadata.design.dto.clientobject.domainmodel.schema.Properties;
import com.authine.common.util.IdWorker;
import com.authine.hermes.app.file.dto.clientobject.DownLoadDTO;
import com.authine.hermes.app.file.feign.FtpFeignServiceI;
import com.authine.hermes.app.launcher.service.ApplicationService;
import com.authine.hermes.app.launcher.service.BOService;
import com.authine.mvp.app.launcher.domain.AttachmentFormat;
import com.authine.mvp.app.launcher.domain.SelectorFormat;
import com.authine.mvp.app.launcher.domain.utills.ApplicationContextUtils;
import com.authine.mvp.app.launcher.dto.bo.cmd.CreateBOCmd;
import com.authine.mvp.app.launcher.dto.bo.cmd.UpdateBOCmd;
import com.authine.mvp.app.launcher.dto.bo.query.expression.*;
import com.authine.mvp.app.launcher.dto.bo.response.BO;
import com.authine.mvp.app.launcher.dto.bo.response.BOList;
import com.authine.mvp.app.launcher.dto.errorcode.ErrorCodeEnum;
import com.authine.mvp.app.launcher.utils.BOUtils;
import com.authine.mvp.app.launcher.utils.ModelRuntimeException;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.http.HttpMethod;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import java.io.*;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.authine.cloudpivot.ext.conf.ApplicationConf.*;
import static com.authine.hermes.app.launcher.service.ApplicationServiceFoundation.CUSTOM_SERVICE;

/**
 * @program: gm-market
 * @description: 市场商品管理
 * @author: wlw
 * @create: 2021-08-05 15:54
 **/
@Path("MarketGoodsManageService")
@Slf4j
public class MarketGoodsManageService extends ApplicationService {
    private FtpFeignServiceI ftpFeignServiceI = ApplicationContextUtils.getBean(FtpFeignServiceI.class);
    private JdbcTemplate jdbcTemplate = ApplicationContextUtils.getBean(JdbcTemplate.class);
    private PunchoutBosiUtils punchoutBosiUtils = new PunchoutBosiUtils();
    private final ExecutorService executor = Executors.newSingleThreadExecutor();

    /**
     * 保存市场商品
     * @return
     */
    @POST
    @Path("saveOrUpdateMarketGoodModels")
    @Operation(summary = "市场商品管理-保存或更新市场商品", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> saveOrUpdateMarketGoodModels(@Parameter MarketGoodsDto goodsDto) {
        Assert.isTrue(Objects.nonNull(goodsDto),"参数不能为空，请检查");
        if(!StringUtils.isEmpty(goodsDto.getStock())&&!StringUtils.isEmpty(goodsDto.getDelivery())
                &&goodsDto.getStock().compareTo(BigDecimal.ZERO)==0&&goodsDto.getDelivery().compareTo(BigDecimal.ZERO) <= 0)
            throw new BizException("当库存为0时，无库存交货期必须大于0");
        if(!StringUtils.isEmpty(goodsDto.getStock())&&!StringUtils.isEmpty(goodsDto.getSafe_stock())
                && Optional.ofNullable(goodsDto.getStock()).orElse(BigDecimal.ZERO).compareTo(goodsDto.getSafe_stock())<= 0)
            throw new BizException("安全库存不能大于库存数量");
        if(StringUtils.isEmpty(goodsDto.getId())) {
            goodsDto.setReview_status(ApproveStatusEnum.APPROVE_ING.getCode());
            goodsDto.setAdjust_pretax_price(goodsDto.getPretax_price());
            goodsDto.setAdjust_price(goodsDto.getPrice());
            goodsDto.setId(String.valueOf(IdWorker.nextId()));
            goodsDto.setType(GoodsTypeEnum.Mall.getCode());
            //供应商id  供应商组织名 前端传递
            OrgVo orgRootOrganization = PmUtil.getOrgOrganization("");
            goodsDto.setVendor_id(PmUtil.orgFormat((orgRootOrganization.getId())));
            goodsDto.setOrg_fullname(orgRootOrganization.getName());
            goodsDto.setMall_goods_type(MallGoodsTypeEnum.IS.getCode());
            goodsDto.setProfile_enabled(goodsDto.getEnabled());
            goodsDto.setFictitious(orgRootOrganization.getVirtual());
            if(StringUtils.isEmpty(goodsDto.getSaled())||!goodsDto.getSaled())
                goodsDto.setReview_status(ApproveStatusEnum.WAIT_COMMIT.getCode());
            Map<String, Object> goodsMap = BoUtils.bo2Map(goodsDto);
            CreateBOCmd createBOCmd = new CreateBOCmd();
            createBOCmd.setSchemaCode(ApplicationConf.GOODES);
            createBOCmd.setData(Collections.singletonList(goodsMap));
            return boService.create(createBOCmd);
        }else {
            BO data = BoServiceUtils.loadByBizObjectId(ApplicationConf.GOODES, goodsDto.getId()).getData();
            Map<String, Object> goods = data.getData();
            Assert.isTrue(Objects.nonNull(goods),"商品不存在");
            goodsDto.setProfile_enabled(goodsDto.getEnabled());
            if(ApproveStatusEnum.APPROVE.getCode().equals(goods.get("review_status"))||ApproveStatusEnum.REJECT.getCode().equals(goods.get("review_status")))
                goodsDto.setReview_status(ApproveStatusEnum.APPROVE_ING.getCode());
            addGoodsHistory(goodsDto.getId());
            Map<String, Object> bo2Map = BoUtils.bo2Map(goodsDto);
            executor.submit(()-> checkCallJZApi(goods,bo2Map));
            return BoServiceUtils.updateBo(ApplicationConf.GOODES,bo2Map);
        }
    }

    /**
     * 比例调整
     * @param adjustmentProportionDto
     */
    @POST
    @Path("adjustmentProportion")
    @Operation(summary = "市场商品管理-比例调整", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> adjustmentProportion(@Parameter AdjustmentProportionDto adjustmentProportionDto){
        Assert.isTrue(Objects.nonNull(adjustmentProportionDto),"参数不能为空，请检查");
        Assert.isTrue(!CollectionUtils.isEmpty(adjustmentProportionDto.getIds()),"商品id不能为空，请检查");
        Assert.isTrue(Objects.nonNull(adjustmentProportionDto.getProportion()),"调整比例不能为空，请检查");
        SingleResponse<BOList> singleResponse = BoServiceUtils.findListBySimple(GOODES, "id", adjustmentProportionDto.getIds(), Operator.IN);
        if(!singleResponse.isSuccess()||CollectionUtils.isEmpty(singleResponse.getData().getData()))throw new BizException("商品查询失败");
        UpdateBOCmd updateBOCmd = new UpdateBOCmd();
        updateBOCmd.setSchemaCode(ApplicationConf.GOODES);
        List<Map<String, Object>> paramMaps = singleResponse.getData().getData().stream().map(goods -> {
            Map<String, Object> paramMap = Maps.newHashMap();
            paramMap.put("id", goods.get("id"));
            paramMap.put("adjust_ratio", new BigDecimal(adjustmentProportionDto.getProportion()).divide(new BigDecimal("100")));
            paramMap.put("adjust_pretax_price", PmUtil.numberFormat(((BigDecimal) goods.get("pretax_price")).multiply(BigDecimal.ONE.add((BigDecimal) paramMap.get("adjust_ratio")))));
            paramMap.put("adjust_price", PmUtil.numberFormat(((BigDecimal) paramMap.get("adjust_pretax_price")).multiply(BigDecimal.ONE.add((BigDecimal) goods.get("tax_rate")))));
            return paramMap;
        }).collect(Collectors.toList());
        updateBOCmd.setData(paramMaps);
        adjustmentProportionDto.getIds().forEach(this::addGoodsHistory);
        executor.submit(()-> {
            adjustmentProportionDto.getIds().forEach(this::addGoodsHistory);
            List<Map<String, Object>> data = singleResponse.getData().getData();
            callJZApi(JZApiEnum.AMOUNT_UPDATE,data);
        });
        return boService.update(updateBOCmd);
    }

    /**
     * 供应商商品导入
     * @param ids
     * @return
     */
    @POST
    @Path("supplierGoodsImport")
    @Operation(summary = "市场商品管理-供应商商品导入", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> supplierGoodsImport(@Parameter  SupplierGoodsImportDto ids){
        Assert.isTrue(!CollectionUtils.isEmpty(ids.getIds()),"参数不能为空，请检查");
        BOList boList = BoServiceUtils.findListBySimple(GOODES, "id", ids, Operator.IN).getData();
        if(!CollectionUtils.isEmpty(boList.getData())){
            UpdateBOCmd updateBOCmd = new UpdateBOCmd();
            updateBOCmd.setSchemaCode(ApplicationConf.GOODES);
            updateBOCmd.setData(
                JSON.parseArray(JSON.toJSONString(boList.getData()), MarketGoodsDto.class).stream().map(t->{
                    Map<String, Object> paramMap = Maps.newHashMap();
                    paramMap.put("id",t.getId());
                    paramMap.put("review_status",ApproveStatusEnum.WAIT_COMMIT.getCode());
                    paramMap.put("adjust_ratio",BigDecimal.ZERO);
                    paramMap.put("adjust_price",Optional.ofNullable(t.getPrice()).orElse(BigDecimal.ZERO));
                    paramMap.put("adjust_pretax_price",Optional.ofNullable(t.getPretax_price()).orElse(BigDecimal.ZERO));
                    paramMap.put("saled",Boolean.FALSE);
                    paramMap.put("enabled",Boolean.TRUE);
                    paramMap.put("mall_goods_type",1);
                    return  paramMap;
                }).collect(Collectors.toList()));
            ids.getIds().forEach(this::addGoodsHistory);
            return boService.update(updateBOCmd);
        }
        return SingleResponse.buildSuccess();
    }

    /**
     * 调整商品上下架
     * @param adjustSaleBatchDto
     * @return
     */
    @POST
    @Path("adjustSale")
    @Operation(summary = "市场商品管理-调整商品上下架", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> adjustSale(@Parameter List<AdjustSaleDto> adjustSaleBatchDto){
        Assert.isTrue(Objects.nonNull(adjustSaleBatchDto),"参数不能为空，请检查");
        Assert.isTrue(!CollectionUtils.isEmpty(adjustSaleBatchDto),"参数不能为空，请检查");
        List<String> goodsIdList = Lists.newArrayList();
        for (AdjustSaleDto adjustSaleDto:adjustSaleBatchDto) {
            BO data = BoServiceUtils.loadByBizObjectId( ApplicationConf.GOODES, adjustSaleDto.getId()).getData();
            Map<String, Object> map = Maps.newHashMap();
            Map<String, Object> marketGoodsBo = Optional.ofNullable(data).map(BO::getData).get();
            //选择单条或多条商品做上下架操作时，对上架状态为否的商品校验商品信息的必填项是否存在为空的情况，必填项全不为空时上架成功，必填项存在为空时上架失败。
            if(adjustSaleDto.getSale()) {
                if(!goodsCheck(marketGoodsBo)){
                    goodsIdList.add((String) marketGoodsBo.get("id"));
                    continue;
                }
                //待提交状态，并且商品由下架状态调整为上架,上架状态变为是，审核为待提交、审核中和已驳回的状态变为审核中状态，审核已通过的状态仍然是已通过状态
                if (ApproveStatusEnum.WAIT_COMMIT.getCode().equals(marketGoodsBo.get("review_status"))||
                        ApproveStatusEnum.REJECT.getCode().equals(marketGoodsBo.get("review_status"))) {
                    map.put("review_status", ApproveStatusEnum.APPROVE_ING.getCode());
                }
            }
            map.put("saled", adjustSaleDto.getSale());
            map.put("id", adjustSaleDto.getId());
            addGoodsHistory(adjustSaleDto.getId());
            BoServiceUtils.updateBo( ApplicationConf.GOODES, map);
            executor.submit(()->callJZApi(JZApiEnum.STATUS_UPDATE,Collections.singletonList(data.getData())));
        }
        if(!CollectionUtils.isEmpty(goodsIdList)){
            String s = String.join(",", goodsIdList);
            throw new BizException("上架失败，下架成功。请编辑完善商品序号："+s+"的必填信息");
        }
        return SingleResponse.buildSuccess();
    }

    /**
     * 物品导入
     * @return
     */
    @POST
    @Path("goodsImport")
    @Operation(summary = "市场商品管理-物品导入", tags = CUSTOM_SERVICE)
    public SingleResponse<List<MarketGoodsVo>> goodsImport(@Parameter ImportFileDto importFileDto)   {
        log.info("[goodsImport]入参 :{}", importFileDto);
        List<Map<String, Object>> masterData = getExcelMaps(importFileDto,ApplicationConf.GOODES);
        log.info("masterData :{}", masterData);
        if (CollectionUtils.isEmpty(masterData)) {
            throw BoUtils.bizException("导入Excel文件没有数据");
        }
        for (int i = 1;i <= masterData.size();i++){
            Map<String, Object> v = masterData.get(i-1);
            commonImportCheck(i, v);

            //启禁用
            v.put("enabled", v.get("enabled"));

            //商品图片
            String images = (String)v.get("images");
            if(!StringUtils.isEmpty(images)){
                List<String> list = Arrays.asList(images.split(","));
                String matching = "(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]";
                for (String l:list) {
                    Assert.isTrue(l.matches(matching),"第"+i+"行商品图片地址不正确");
                }
                v.put("images",list);
            }

            String numMatching = "^(\\-|\\+)?\\d+(\\.\\d+)?$";
            //长宽高重
            String length = (String)v.get("length");
            if(!StringUtils.isEmpty(length)) {
                Assert.isTrue(length.matches(numMatching), "第" + i + "行长格式不正确");
            }


            String width = (String)v.get("width");
            if(!StringUtils.isEmpty(width)) {
                Assert.isTrue(width.matches(numMatching), "第" + i + "行宽格式不正确");
            }

            String height = (String)v.get("height");
            if(!StringUtils.isEmpty(height)) {
                Assert.isTrue(height.matches(numMatching), "第" + i + "行高格式不正确");
            }

            String weight = (String)v.get("weight");
            if(!StringUtils.isEmpty(weight)) {
                Assert.isTrue(weight.matches(numMatching), "第" + i + "行重格式不正确");
            }
        }
           return SingleResponse.of(JSON.parseArray(JSON.toJSONString(masterData),MarketGoodsVo.class));
    }

    private void commonImportCheck(int i, Map<String, Object> v) {
        //品牌
        String brand = (String) v.get("brand");
        Assert.isTrue(!StringUtils.isEmpty(brand), "第" + i + "行品牌不能为空");
        Assert.isTrue(brand.length() < 200, "第" + i + "行品牌字符长度不能超过200");

        //商品名称
        String name = (String) v.get("name");
        Assert.isTrue(!StringUtils.isEmpty(name), "第" + i + "行商品不能为空");
        Assert.isTrue(name.length() < 200, "第" + i + "行商品字符长度不能超过200");

        //型号
        String model = (String) v.get("model");
        Assert.isTrue(!StringUtils.isEmpty(model), "第" + i + "行型号不能为空");
        Assert.isTrue(model.length() < 200, "第" + i + "行型号字符长度不能超过200");

        //规格
        String spec = (String) v.get("spec");
        Assert.isTrue(!StringUtils.isEmpty(spec), "第" + i + "行规格不能为空");
        Assert.isTrue(spec.length() < 200, "第" + i + "行规格字符长度不能超过200");

        //平台目录
        String catalog = (String) v.get("catalog");
        Assert.isTrue(!StringUtils.isEmpty(catalog), "第" + i + "行平台目录不能为空");

        //报价单位
        String unit = (String) v.get("unit");
        Assert.isTrue(!StringUtils.isEmpty(unit), "第" + i + "行平台报价单位不能为空");

        //包装内数量
        String package_num = (String) v.get("package_num");
        Assert.isTrue(!StringUtils.isEmpty(package_num), "第" + i + "平台包装内数量不能为空");
        Assert.isTrue(Pattern.matches("^\\d+(\\.\\d+)?", package_num), "第" + i + "行包装内数量必须为阿拉伯数字");

        //包装单位
        String package_unit = (String) v.get("package_unit");
        Assert.isTrue(!StringUtils.isEmpty(package_unit), "第" + i + "行包装单位不能为空");

        //最小起订量
        String min_order = (String) v.get("min_order");
        Assert.isTrue(!StringUtils.isEmpty(min_order), "第" + i + "行包装单位不能为空");
        Assert.isTrue(Pattern.matches("^\\d+(\\.\\d+)?", min_order), "第" + i + "行最小起订量必须为阿拉伯数字");

        //税率
        String tax_rate = (String) v.get("tax_rate");
        Assert.isTrue(!StringUtils.isEmpty(tax_rate), "第" + i + "行税率不能为空");
        Assert.isTrue(Pattern.matches("^\\d+(\\.\\d+)?%?", tax_rate), "第" + i + "行税率不正确");
        if (tax_rate.contains("%")) {
            v.put("tax_rate", new BigDecimal(tax_rate.replace("%", "")).divide(new BigDecimal(100)));
        }

        //未税单价
        String pretax_price = (String) v.get("pretax_price");
        Assert.isTrue(!StringUtils.isEmpty(pretax_price), "第" + i + "行未税单价不能为空");
        Assert.isTrue(Pattern.matches("^\\d+(\\.\\d+)?", pretax_price), "第" + i + "行未税单价必须为阿拉伯数字");

        //含税单价
        v.put("price", new BigDecimal(pretax_price).multiply(BigDecimal.ONE.add(new BigDecimal(tax_rate))));

        //发货地
        String delivery_place = (String) v.get("delivery_place");
        Assert.isTrue(!StringUtils.isEmpty(delivery_place), "第" + i + "行发货地不能为空");
        Assert.isTrue(delivery_place.contains("/"), "第" + i + "行发货地格式不正确");

        //销售有效期至（日期）
        String expiry = (String) v.get("expiry");
        Assert.isTrue(!StringUtils.isEmpty(expiry), "第" + i + "行有效期不能为空");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        try {
            sdf.parse(expiry);
        } catch (ParseException e) {
            throw new BizException("第" + i + "行有效期格式不正确");
        }

        //库存数量
        String stock = (String) v.get("stock");
        Assert.isTrue(!StringUtils.isEmpty(stock), "第" + i + "行库存数量不能为空");
        Assert.isTrue(Pattern.matches("^\\d+(\\.\\d+)?", stock), "第" + i + "行库存数量必须为阿拉伯数字");

        //无库存交货期(天)
        String delivery = (String) v.get("delivery");
        if (!StringUtils.isEmpty(delivery)) {
            Assert.isTrue(Pattern.matches("^\\d+(\\.\\d+)?", delivery), "第" + i + "行无库存交货期(天)必须为阿拉伯数字");
            if (new BigDecimal(stock).compareTo(BigDecimal.ZERO) == 0 && new BigDecimal(delivery).compareTo(BigDecimal.ZERO) <= 0) {
                throw new BizException("当库存为0时，无库存交货期必须大于0");
            }
        }

        //启禁用
        String enabled = (String)v.get("enabled");
        v.put("enabled", "启用".equals(enabled));

    }

    /**
     * 物品导入
     * @return
     */
    @POST
    @Path("supplierGoodsImport")
    @Operation(summary = "供应商商品管理-物品导入", tags = CUSTOM_SERVICE)
    public SingleResponse<List<MarketGoodsVo>> supplierGoodsImport(@Parameter ImportFileDto importFileDto) throws FileNotFoundException {
        log.info("[supplierGoodsImport]入参 :{}", importFileDto);
        List<Map<String, Object>> masterData = getExcelMaps(importFileDto,ApplicationConf.GOODES);
        log.info("masterData :{}", masterData);
        if (CollectionUtils.isEmpty(masterData)) {
            throw BoUtils.bizException("导入Excel文件没有数据");
        }
        for (int i = 1;i <= masterData.size();i++){
            Map<String, Object> v = masterData.get(i-1);
            //校验
            commonImportCheck(i, v);

            //商品图片
            String images = (String)v.get("images");
            if(!StringUtils.isEmpty(images)){
                List<String> list = Arrays.asList(images.split(","));
                String matching = "(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]";
                for (String l:list) {
                    Assert.isTrue(l.matches(matching),"第"+i+"行商品图片地址不正确");
                }
            }

            String numMatching = "^(\\-|\\+)?\\d+(\\.\\d+)?$";
            //长宽高重
            String length = (String)v.get("length");
            if(!StringUtils.isEmpty(length)) {
                Assert.isTrue(length.matches(numMatching), "第" + i + "行长格式不正确");
            }

            String width = (String)v.get("width");
            if(!StringUtils.isEmpty(width)) {
                Assert.isTrue(width.matches(numMatching), "第" + i + "行宽格式不正确");
            }

            String height = (String)v.get("height");
            if(!StringUtils.isEmpty(height)) {
                Assert.isTrue(height.matches(numMatching), "第" + i + "行高格式不正确");
            }

            String weight = (String)v.get("weight");
            if(!StringUtils.isEmpty(weight)) {
                Assert.isTrue(weight.matches(numMatching), "第" + i + "行重格式不正确");
            }
        }
        return SingleResponse.of(JSON.parseArray(JSON.toJSONString(masterData),MarketGoodsVo.class));
    }

    private List<Map<String, Object>> getExcelMaps(ImportFileDto importFileDto,String code) {
        String refId = importFileDto.getRefId();
        if (StringUtils.isEmpty(importFileDto.getRefId())) {
            throw new ModelRuntimeException(ErrorCodeEnum.BIZ_PARAMS_ERR, "文件id不存在");
        }
        String url = String.format(uploadFile, refId);
        //File file = new File("D:\\mall-vendor-goods-template.xlsx");
        log.info("文件下载地址:{}",url);
        FtpFeignServiceI ftpFeignServiceI = ApplicationContextUtils.getBean(FtpFeignServiceI.class);
        SingleResponse<DownLoadDTO> response = ftpFeignServiceI.downloadBytes(importFileDto.getRefId());
        log.info("入参 :{}", importFileDto);
        if (StringUtils.isEmpty(refId)) {
            throw new ModelRuntimeException(ErrorCodeEnum.BIZ_PARAMS_ERR, "文件id不存在");
        }
        if(!response.isSuccess()){
            throw BoUtils.bizException("获取文件失败".concat(response.getErrMessage()));
        }
        if(response.getData()==null){
            throw BoUtils.bizException("文件流数据为空");
        }
        InputStream inputStream = new ByteArrayInputStream(response.getData().getImageBytes());
        //InputStream inputStream = new FileInputStream(file);
        if (inputStream == null)
            throw BoUtils.bizException("获取文件流数据为空");
        ByteArrayOutputStream copyTempStream = ExcelUtils.cloneInputStream(inputStream);
        if (copyTempStream == null)
            throw BoUtils.bizException("获取文件流复制数据为空");
        //商品模型元数据属性
        List<Properties> goodsProperties = PropertiesUtils.getSchemaProperties(environment.getProperty(BOUtils.APPCODE), ApplicationConf.GOODES);
        // 将文件转换为数据
        return ExcelImportUtils.bbcPreValidateImportByFixedOnInputStream(code, copyTempStream, 0);
    }


    @POST
    @Path("saveGoodsImport")
    @Operation(summary = "市场商品管理-物品导入提交", tags = CUSTOM_SERVICE)
    public SingleResponse saveGoodsImport(@Parameter List<MarketGoodsDto> marketGoodsDtos) {
        Assert.isTrue(!CollectionUtils.isEmpty(marketGoodsDtos), "参数不能为空");
        int updateCount = 0;
        int saveCount = 0;
        for (int i = 1; i <= marketGoodsDtos.size(); i++) {
            MarketGoodsDto goodsDto = marketGoodsDtos.get(i - 1);
            goodsDto.setReview_status(ApproveStatusEnum.WAIT_COMMIT.getCode());
            goodsDto.setAdjust_pretax_price(goodsDto.getPretax_price());
            goodsDto.setAdjust_price(goodsDto.getPrice());
            goodsDto.setId(String.valueOf(IdWorker.nextId()));
            OrgVo orgRootOrganization = PmUtil.getOrgOrganization("");
            goodsDto.setVendor_id(PmUtil.orgFormat(orgRootOrganization.getId()));
            goodsDto.setOrg_fullname(orgRootOrganization.getName());
            goodsDto.setFictitious(orgRootOrganization.getVirtual());
            goodsDto.setMall_goods_type(MallGoodsTypeEnum.IS.getCode());
            goodsDto.setType(GoodsTypeEnum.Mall.getCode());
            goodsDto.setProfile_enabled(goodsDto.getEnabled());
            //目录反查id
            String catalogName = goodsDto.getCatalog().trim();
            List<Map<String, Object>> catalogList = BoServiceUtils.findListBySimple(ApplicationConf.CATALOG, "name", catalogName, Operator.EQ).getData().getData();
            Assert.isTrue(!CollectionUtils.isEmpty(catalogList), "第" + i + "行平台目录查询无此类，请修改后重新导入");
            goodsDto.setCatalog_id((String) Objects.requireNonNull(CollectionUtils.firstElement(catalogList)).get("id"));

            //报价单位反查id
            String unitName = goodsDto.getUnit().trim();
            List<Map<String, Object>> unitList = BoServiceUtils.findListBySimple(ApplicationConf.UNIT, "name", unitName, Operator.EQ).getData().getData();
            Assert.isTrue(!CollectionUtils.isEmpty(unitList), "第" + i + "行报价单位查询无此类，请修改后重新导入");
            goodsDto.setUnit_id((String) Objects.requireNonNull(CollectionUtils.firstElement(unitList)).get("id"));

            //包装单位反查id
            String packageName = goodsDto.getPackage_unit().trim();
            List<Map<String, Object>> packageUnitList = BoServiceUtils.findListBySimple(ApplicationConf.UNIT, "name", packageName, Operator.EQ).getData().getData();
            Assert.isTrue(!CollectionUtils.isEmpty(packageUnitList), "第" + i + "行报价单位查询无此类，请修改后重新导入");
            goodsDto.setPackage_unit_id((String) Objects.requireNonNull(CollectionUtils.firstElement(packageUnitList)).get("id"));

            //税率值反查id
            BigDecimal tax_rate = goodsDto.getTax_rate();
            List<Map<String, Object>> taxRateList = BoServiceUtils.findListBySimple(ApplicationConf.TAX_RATE, "tax_rate", tax_rate.toString(), Operator.EQ).getData().getData();
            Assert.isTrue(!CollectionUtils.isEmpty(taxRateList), "第" + i + "行税率查询无此类，请修改后重新导入");
            goodsDto.setTax_rate_id((String) Objects.requireNonNull(CollectionUtils.firstElement(taxRateList)).get("id"));

            //商品主图
            if (!StringUtils.isEmpty(goodsDto.getImages())) {
                List<ImageDto> imageList = Lists.newArrayList();
                Object[] images = ((List) goodsDto.getImages()).toArray();
                for (int j = 0; j < images.length; j++) {
                    String suffix = ((String)images[j]).substring((((String)images[j]).lastIndexOf('.')));
                    MultipartFile multipartFile = new MockMultipartFile("file", IdWorker.nextId() + suffix, "text/plain", FileUtil.getFile((String)images[j]));
                    AttachmentRes res = ftpFeignServiceI.uploadAttachment(multipartFile).getData();
                    imageList.add(ImageDto.builder().fileSize(res.getFileSize()).id(res.getRefId()).mimeType(res.getMimeType()).name(res.getName()).build());
                }
                goodsDto.setImages(imageList);
            }

            //商品详情图
            if (!StringUtils.isEmpty(goodsDto.getGodds_detail_images())) {
                List<ImageDto> imageDetailList = Lists.newArrayList();
                String[] detailImages = ((String) goodsDto.getImages()).split(",");
                for (int j = 0; j < detailImages.length; j++) {
                    String suffix = detailImages[i].substring(detailImages[j].lastIndexOf('.'));
                    MultipartFile multipartFile = new MockMultipartFile("file", IdWorker.nextId() + suffix, "text/plain", FileUtil.getFile(detailImages[i]));
                    AttachmentRes res = ftpFeignServiceI.uploadAttachment(multipartFile).getData();
                    imageDetailList.add(ImageDto.builder().fileSize(res.getFileSize()).id(res.getRefId()).mimeType(res.getMimeType()).name(res.getName()).build());
                }
                goodsDto.setGodds_detail_images(imageDetailList);
            }
            //校验是否重复商品
            ComplexCondition condition = new ComplexCondition();
            condition.setNature(Nature.AND);
            condition.getConditions().add(new SimpleCondition("catalog", Operator.EQ, goodsDto.getCatalog().trim()));
            condition.getConditions().add(new SimpleCondition("name", Operator.EQ, goodsDto.getName().trim()));
            condition.getConditions().add(new SimpleCondition("brand", Operator.EQ, goodsDto.getBrand().trim()));
            condition.getConditions().add(new SimpleCondition("spec", Operator.EQ, goodsDto.getSpec().trim()));
            condition.getConditions().add(new SimpleCondition("model", Operator.EQ, goodsDto.getModel().trim()));
            condition.getConditions().add(new SimpleCondition("vendor_id", Operator.LIKE, orgRootOrganization.getId()));
            condition.getConditions().add(new SimpleCondition("unit", Operator.EQ, goodsDto.getUnit().trim()));
            condition.getConditions().add(new SimpleCondition("package_unit", Operator.EQ, goodsDto.getPackage_unit().trim()));
            condition.getConditions().add(new SimpleCondition("package_num", Operator.EQ, goodsDto.getPackage_num()));
            condition.getConditions().add(new SimpleCondition("type", Operator.IN, Arrays.asList(GoodsTypeEnum.Mall.getCode(), GoodsTypeEnum.Virtual.getCode())));
            SingleResponse<BOList> singleResponse = BoServiceUtils.findListByCondition(GOODES, condition);
            if (!CollectionUtils.isEmpty(singleResponse.getData().getData())) {
                BoServiceUtils.updateBo(GOODES, BoUtils.bo2Map(goodsDto));
                updateCount++;
            } else {
                BoServiceUtils.createBo(ApplicationConf.GOODES,BoUtils.bo2Map(goodsDto));
                saveCount++;
            }
        }
        return SingleResponse.of("保存成功！保存商品"+saveCount+"条，更新商品"+updateCount+"条");
    }

    @POST
    @Path("approve")
    @Operation(summary = "市场商品管理-商品审批", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> approve(@Parameter GoodsApproveDto goodsApproveDto) {
        Assert.isTrue(Objects.nonNull(goodsApproveDto),"参数不能为空，请检查");
        Assert.isTrue(!CollectionUtils.isEmpty(goodsApproveDto.getIds()),"商品id不能为空，请检查");
        Assert.isTrue(!StringUtils.isEmpty(goodsApproveDto.getReview_status()),"审批状态不能为空，请检查");
        List<Map<String, Object>> maps = goodsApproveDto.getIds().stream().map(v -> {
            BO data = BoServiceUtils.loadByBizObjectId(GOODES, v).getData();
            if (Objects.isNull(data) || Objects.isNull(data.getData())) throw new BizException("商品不存在");
            Map<String, Object> map = Maps.newHashMap();
            map.put("id", v);
            map.put("review_status", goodsApproveDto.getReview_status());
            map.put("review_content", goodsApproveDto.getComment());
            return map;
        }).collect(Collectors.toList());
        goodsApproveDto.getIds().forEach(i->{
                this.addGoodsHistory(i);
            SingleResponse<BO> response = BoServiceUtils.loadByBizObjectId(GOODES, i);
            Map<String, Object> map = response.getData().getData();
            if(response.isSuccess()&&Objects.nonNull(response.getData())&&Objects.nonNull(map)){
                //触发冀中商城导入行为
                executor.submit(()->callJZApi(JZApiEnum.IMPORT_UPDATE, Collections.singletonList(map)));
            }
        });
        return BoServiceUtils.batchUpdateBo(ApplicationConf.GOODES, maps);
    }

    /**
     * 模板文件下载
     */
    @POST
    @Path("exportTemplateFile")
    @Operation(summary = "市场商品管理-模板下载", tags = CUSTOM_SERVICE)
    public void exportTemplateFile(@Parameter ExportTemplateFileDto exportTemplateFileDto) {
        Assert.isTrue(Objects.nonNull(exportTemplateFileDto),"参数不能为空");
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = servletRequestAttributes.getResponse();
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        //转base64并返回
        try {
            InputStream endFileStream = this.getClass().getClassLoader().getResourceAsStream(exportTemplateFileDto.getFileName());
            log.info("数据流:{}",endFileStream);
            byte[] bytes = IOUtils.toByteArray(endFileStream);
            String encoded = "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".concat(Base64.getEncoder().encodeToString(bytes));
            response.getWriter().write(encoded);
        } catch (Exception e2) {
            log.error("导出文件异常，error is :", e2);
        }
    }


    @POST
    @Path("mallGoodsListPage")
    @Operation(summary = "市场商品管理-商品管理列表", tags = CUSTOM_SERVICE)
    public MultiResponse<MallGoodPageVo> mallGoodsListPage(@Parameter MallGoodsListPageQuery mallGoodsListPageQuery) {
        Assert.isTrue(!StringUtils.isEmpty(mallGoodsListPageQuery), "参数不能为空");
        StringBuilder querySql = new StringBuilder("select " +
                "id," +
                "review_status," +
                "catalog," +
                "brand," +
                "name," +
                "model," +
                "spec," +
                "unit," +
                "delivery," +
                "min_order," +
                "pretax_price," +
                "price," +
                "package_num," +
                "adjust_price," +
                "adjust_pretax_price," +
                "adjust_ratio," +
                "type," +
                "tax_rate," +
                "safe_stock," +
                "mall_featured," +
                "vendor_id," +
                "org_fullname," +
                "stock_delivery," +
                "expiry," +
                "enabled," +
                "saled," +
                "createdTime," +
                "modifiedtime," +
                "package_unit," +
                "package_unit_id," +
                "unit_id," +
                "stock," +
                "type," +
                "delivery_place," +
                "images," +
                "description," +
                "godds_detail_images," +
                "review_content " +
                "from " + COMMODITYMATERIALS_GOODES +
                " where deleted = 0 ");
        StringBuilder countSql = new StringBuilder("select count(1) as count" +
                " from " + COMMODITYMATERIALS_GOODES +
                " where deleted = 0 ");

        buildQueryMallGoodsPage(mallGoodsListPageQuery, querySql);
        buildQueryMallGoodsPage(mallGoodsListPageQuery, countSql);

        Integer count = jdbcTemplate.queryForObject(countSql.toString(), (rs, rowNum) ->
                rs.getInt("count")
        );

        int index = mallGoodsListPageQuery.getPageIndex()*mallGoodsListPageQuery.getPageSize();
        querySql.append(" limit ").append(index).append(",").append(mallGoodsListPageQuery.getPageSize());
        log.info("商品分页查询sql:"+querySql.toString());
        List<MallGoodPageVo> list = jdbcTemplate.query(querySql.toString(), (rs, rowNum) ->
                MallGoodPageVo.builder()
                        .brand(rs.getString("brand"))
                        .id(rs.getString("id"))
                        .catalog(rs.getString("catalog"))
                        .delivery(rs.getBigDecimal("delivery"))
                        .pretax_price(rs.getBigDecimal("pretax_price"))
                        .price(rs.getBigDecimal("price"))
                        .review_status(rs.getString("review_status"))
                        .name(rs.getString("name"))
                        .spec(rs.getString("spec"))
                        .model(rs.getString("model"))
                        .expiry(rs.getTimestamp("expiry"))
                        .min_order(rs.getBigDecimal("min_order"))
                        .enabled(rs.getBoolean("enabled"))
                        .saled(rs.getBoolean("saled"))
                        .unit(rs.getString("unit"))
                        .org_fullname(rs.getString("org_fullname"))
                        .createdTime(rs.getTimestamp("createdTime"))
                        .safe_stock(rs.getBigDecimal("safe_stock"))
                        .tax_rate(rs.getBigDecimal("tax_rate"))
                        .unit(rs.getString("unit"))
                        .vendor_id(JSON.parseObject(rs.getString("vendor_id"), SelectorFormat.class))
                        .modifiedtime(rs.getTimestamp("modifiedtime"))
                        .review_content(rs.getString("review_content"))
                        .adjust_pretax_price(rs.getBigDecimal("adjust_pretax_price"))
                        .adjust_price(rs.getBigDecimal("adjust_price"))
                        .adjust_ratio(rs.getBigDecimal("adjust_ratio"))
                        .mall_featured(rs.getBigDecimal("mall_featured"))
                        .package_num(rs.getBigDecimal("package_num"))
                        .package_unit(rs.getString("package_unit"))
                        .package_unit_id(rs.getString("package_unit_id"))
                        .unit_id(rs.getString("unit_id"))
                        .stock(rs.getBigDecimal("stock"))
                        .delivery_place(rs.getString("delivery_place"))
                        .type(rs.getInt("type"))
                        .stock_delivery(rs.getBigDecimal("stock_delivery"))
                        .description(rs.getString("description"))
                        .images(JSONObject.parseArray(rs.getString("images")))
                        .godds_detail_images(JSONObject.parseArray(rs.getString("godds_detail_images")))
                        .typeName(Objects.isNull(GoodsTypeEnum.get(String.valueOf(rs.getInt("type"))))?"":
                                GoodsTypeEnum.get(String.valueOf(rs.getInt("type"))).getDesc())
                        .mall_featured_name(BigDecimal.ONE.compareTo(rs.getBigDecimal("mall_featured")) == 0 ?"精品":"非精品")
                        .build());
        return MultiResponse.of(list, count);
    }

    @POST
    @Path("batchAdjust")
    @Operation(summary = "市场商品管理-批量调整", tags = CUSTOM_SERVICE)
    public SingleResponse batchAdjust(@Parameter BatchAdjustDto batchAdjustDto){
        Assert.isTrue(Objects.nonNull(batchAdjustDto), "参数不能为空");
        Assert.isTrue(!StringUtils.isEmpty(batchAdjustDto.getType()), "type不能为空");
        Assert.isTrue(!StringUtils.isEmpty(batchAdjustDto.getAdjustDtoList()), "调整参数不能为空");
        List<Map<String, Object>> goods = null;
        if(1 == batchAdjustDto.getType()) {
             goods = batchAdjustDto.getAdjustDtoList().stream().map(v -> {
                Map<String, Object> map = Maps.newHashMap();
                map.put("id", v.getId());
                map.put("pretax_price", v.getAdjustCosts());
                map.put("price", v.getAdjustCosts().multiply(BigDecimal.ONE.add(v.getTax_rate())));
                if (!StringUtils.isEmpty(v.getAdjust_ratio())) {
                    map.put("adjust_pretax_price", v.getAdjustCosts().multiply(BigDecimal.ONE.add(v.getAdjust_ratio())));
                    map.put("adjust_price", ((BigDecimal) map.get("adjust_pretax_price")).multiply(BigDecimal.ONE.add(v.getTax_rate())));
                }
                 SingleResponse<BO> response = BoServiceUtils.loadByBizObjectId(GOODES, v.getId());
                if(response.isSuccess()&&!StringUtils.isEmpty(response.getData().getData())){
                    executor.submit(()->callJZApi(JZApiEnum.AMOUNT_UPDATE,Collections.singletonList(response.getData().getData())));
                }
                return map;
            }).collect(Collectors.toList());
        }
        if(2 == batchAdjustDto.getType()){
            goods = batchAdjustDto.getAdjustDtoList().stream().map(v -> {
                Map<String, Object> map = Maps.newHashMap();
                map.put("id", v.getId());
                map.put("stock", v.getAdjustStock());
                SingleResponse<BO> response = BoServiceUtils.loadByBizObjectId(GOODES, v.getId());
                if(response.isSuccess()&&!StringUtils.isEmpty(response.getData().getData())){
                    executor.submit(()->callJZApi(JZApiEnum.INVENTORY_UPDATE,Collections.singletonList(response.getData().getData())));
                }
                return map;
            }).collect(Collectors.toList());
        }
        return BoServiceUtils.batchUpdateBo(GOODES,goods);
    }

    @POST
    @Path("deleteMallGoodsExport")
    @Operation(summary = "市场商品管理-删除", tags = CUSTOM_SERVICE)
    public SingleResponse deleteMallGoodsExport(@Parameter DeleteMallGoodsExport deleteMallGoodsExport) {
        Assert.isTrue(Objects.nonNull(deleteMallGoodsExport),"参数不能为空");
        Assert.isTrue(!CollectionUtils.isEmpty(deleteMallGoodsExport.getIds()),"参数不能为空");
         deleteMallGoodsExport.getIds().forEach(i -> {
            BoServiceUtils.delete(GOODES,i);
        });
         return SingleResponse.buildSuccess();
    }


    @POST
    @Path("mallGoodsExport")
    @Operation(summary = "市场商品管理-导出", tags = CUSTOM_SERVICE)
    public SingleResponse mallGoodsExport(@Parameter ExportDto exportDto) {
        Assert.isTrue(!StringUtils.isEmpty(exportDto),"参数不能为空");
        Assert.isTrue(!CollectionUtils.isEmpty(exportDto.getIds()),"id不能为空");
        Assert.isTrue(!StringUtils.isEmpty(exportDto.getExportFileType()),"文件类型不能为空");

        BOList data = BoServiceUtils.findListBySimple(ApplicationConf.GOODES, "id", exportDto.getIds(), Operator.IN).getData();
        Assert.isTrue(!CollectionUtils.isEmpty(data.getData()),"查询商品不存在");
        ReportRecord record = ReportRecord.builder()
                .code("goods_manage_report")
                .type(Optional.ofNullable(FileExportEnum.get(exportDto.getExportFileType())).orElseThrow(()->new BizException("文件类型不支持")).getCode())
                .data(data.getData().stream().map(v->{
                    Map<String, Object> map = Maps.newHashMap();
                    map.put("brand",v.get("brand"));
                    map.put("id",v.get("id"));
                    map.put("catalog",v.get("catalog"));
                    map.put("name",v.get("name"));
                    map.put("model",v.get("model"));
                    map.put("spec",v.get("spec"));
                    map.put("unit",v.get("unit"));
                    map.put("packageNum",PmUtil.numberFormat((BigDecimal)v.get("package_num")).toString());
                    map.put("packageUnit",v.get("package_unit"));
                    map.put("delivery",v.get("delivery"));
                    map.put("minOrder",PmUtil.numberFormat((BigDecimal)v.get("min_order")).toString());
                    map.put("pretaxPrice",PmUtil.numberFormat((BigDecimal)v.get("pretax_price")).toString());
                    map.put("price",PmUtil.numberFormat((BigDecimal)v.get("price")).toString());
                    map.put("taxRate",PmUtil.numberFormat((BigDecimal)v.get("tax_rate")).toString());
                    map.put("stock",PmUtil.numberFormat((BigDecimal)v.get("stock")).toString());
                    map.put("orgFullname",v.get("org_fullname"));
                    map.put("time",v.get("createdTime"));
                    map.put("expiry",v.get("expiry"));
                    map.put("saled",1==(Integer)v.get("saled"));
                    map.put("enabled",1==(Integer)v.get("enabled"));
                    return map;
                }).collect(Collectors.toList()))
                .build();
        Map singleResponse = RestTemplateUtil.rest(Objects.requireNonNull(PmUtil.getUrl(systemManagement)).concat(EXPORT_REPORT_URL), record, HttpMethod.POST);
        SingleResponse response = BoUtils.Map2Bo(singleResponse, SingleResponse.class);
        Assert.isTrue(response.isSuccess(),response.getErrMessage());
        return  SingleResponse.of(singleResponse.get("data"));
    }

    @POST
    @Path("setCoreGoods")
    @Operation(summary = "供应商商品管理-设置为核心商品", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> setCoreGoods(@Parameter List<String> ids) {
        Assert.isTrue(!CollectionUtils.isEmpty(ids), "参数不能为空");
        BOList data = BoServiceUtils.findListBySimple(GOODES, "id", ids, Operator.IN).getData();
        Assert.isTrue(!CollectionUtils.isEmpty(data.getData()),"商品信息获取失败");
        List<String> idList = data.getData().stream().map(t -> (String) t.get("id")).collect(Collectors.toList());
        ids.removeAll(idList);
        if(!CollectionUtils.isEmpty(ids)){
            throw new BizException("商品序列号："+String.join(",",ids)+"不存在");
        }
        List<Map<String, Object>> maps = idList.stream().map(i -> {
            Map<String, Object> map = Maps.newHashMap();
            map.put("id", i);
            map.put("core", true);
            return map;
        }).collect(Collectors.toList());
        return BoServiceUtils.batchUpdateBo(GOODES,maps);
    }

    @POST
    @Path("queryCustomerList")
    @Operation(summary = "供应商商品管理-客户列表查询", tags = CUSTOM_SERVICE)
    public MultiResponse queryCustomerList(@Parameter CustomerListPageQuery customerListPageQuery) {
        Assert.isTrue(Objects.nonNull(customerListPageQuery), "参数不能为空");
        String loginId = RequestContext.getCorpLoginId();
        Assert.isTrue(!StringUtils.isEmpty(loginId), "未登录");
        ComplexCondition condition = new ComplexCondition();
        condition.setNature(Nature.AND);
        condition.getConditions().add(new SimpleCondition("deleted", Operator.EQ, 0));
        if (!PmUtil.isPm())
            condition.getConditions().add(new SimpleCondition("target_organization_id", Operator.LIKE, PmUtil.getOrgOrganization("").getId()));
        BOList data = BoServiceUtils.easyList(condition, customerListPageQuery.getPageSize(), customerListPageQuery.getPageIndex(), ORGANIZATION_RELATIONSHIP).getData();
        return MultiResponse.of(data.getData(), data.getTotal());
    }


    @POST
    @Path("joinCustomerMall")
    @Operation(summary = "供应商商品管理-转入客户商城", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> joinCustomerMall(@Parameter JoinCustomerMallDto joinCustomerMallDto) {
        Assert.isTrue(Objects.nonNull(joinCustomerMallDto), "参数不能为空");
        Assert.isTrue(!CollectionUtils.isEmpty(joinCustomerMallDto.getIds()), "商品id不能为空");
        Assert.isTrue(!StringUtils.isEmpty(joinCustomerMallDto.getOrgId()), "客户id不能为空");
        BOList data = BoServiceUtils.findListBySimple(GOODES, "id", joinCustomerMallDto.getIds(), Operator.IN).getData();
        BO bo = BoServiceUtils.loadByBizObjectId(ORGANIZATION, joinCustomerMallDto.getOrgId()).getData();
        if(Objects.isNull(bo.getData()))
            throw new BizException("客户信息有误");
        List<Map<String, Object>> maps = data.getData().stream().map(t -> {
            String id = (String) t.get("id");
            ComplexCondition condition = new ComplexCondition();
            condition.setNature(Nature.AND);
            condition.getConditions().add(new SimpleCondition("relation_goods_id", Operator.EQ,t.get("id")));
            condition.getConditions().add(new SimpleCondition("organization_id",Operator.LIKE,joinCustomerMallDto.getOrgId()));
            condition.getConditions().add(new SimpleCondition("type",Operator.EQ,GoodsTypeEnum.EnterpriseMall.getCode()));
            BOList goods = BoServiceUtils.findListByCondition(GOODES, condition).getData();
            if(!CollectionUtils.isEmpty(goods.getData()))
                throw new BizException("商品编号:" + id + " 已经转入该客户商城，请勿重复转入");
            t.put("relation_goods_id", id);
            t.put("organization_id", PmUtil.orgFormat((String) bo.getData().get("id")));
            t.put("organization_name", bo.getData().get("name"));
            t.put("type",GoodsTypeEnum.EnterpriseMall.getCode());
            t.put("id", String.valueOf(IdWorker.nextId()));
            return t;
        }).collect(Collectors.toList());
        return BoServiceUtils.batchCreateBo(GOODES,maps);
    }

    private ByteArrayInputStream getFileOutputStream(String refId) {
        if (StringUtils.isEmpty(refId)) {
            throw new ModelRuntimeException(ErrorCodeEnum.BIZ_PARAMS_ERR, "文件id不存在");
        }
        String url = String.format(uploadFile, refId);
        //File file = new File("D:\\mall-vendor-goods-template.xlsx");
        log.info("文件下载地址:{}",url);
        FtpFeignServiceI ftpFeignServiceI = ApplicationContextUtils.getBean(FtpFeignServiceI.class);
        SingleResponse<DownLoadDTO> response = ftpFeignServiceI.downloadBytes(refId);
        if (StringUtils.isEmpty(refId)) {
            throw new ModelRuntimeException(ErrorCodeEnum.BIZ_PARAMS_ERR, "文件id不存在");
        }
        if(!response.isSuccess()){
            throw BoUtils.bizException("获取文件失败".concat(response.getErrMessage()));
        }
        if(response.getData()==null){
            throw BoUtils.bizException("文件流数据为空");
        }
        return new ByteArrayInputStream(response.getData().getImageBytes());
    }


//-----------------------------------------------------分割线-----------------------------------------------------------------//



    private void handleField(List<Map<String,Object>> list){
        list.stream().map(m->{
            if (StringUtils.isEmpty(m.get("createdBy")))
                m.put("createdBy", BoUtils.Map2Bo((Map) m.get("createdBy"), SelectorFormat.class).getId());
            if (StringUtils.isEmpty(m.get("createdDept")))
                m.put("createdDept", BoUtils.Map2Bo((Map) m.get("createdDept"), SelectorFormat.class).getId());
            if (StringUtils.isEmpty(m.get("owner")))
                m.put("owner", BoUtils.Map2Bo((Map) m.get("owner"), SelectorFormat.class).getId());
            if (StringUtils.isEmpty(m.get("ownerDept")))
                m.put("ownerDept", BoUtils.Map2Bo((Map) m.get("ownerDept"), SelectorFormat.class).getId());
            if (StringUtils.isEmpty(m.get("modifiedBy")))
                m.put("modifiedBy", BoUtils.Map2Bo((Map) m.get("modifiedBy"), SelectorFormat.class).getId());
            return m;
        });
    }


    private void buildQueryMallGoodsPage(MallGoodsListPageQuery mallGoodsListPageQuery, StringBuilder querySql) {
        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getId()))
            querySql.append(" and id  = '").append(mallGoodsListPageQuery.getId()).append("'");
        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getName()))
            querySql.append(" and name  = '").append(mallGoodsListPageQuery.getName()).append("'");
        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getBrand()))
            querySql.append(" and brand  = '").append(mallGoodsListPageQuery.getBrand()).append("'");
        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getCatalog()))
            querySql.append(" and catalog  = '").append(mallGoodsListPageQuery.getCatalog()).append("'");
        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getModel()))
            querySql.append(" and model  = '").append(mallGoodsListPageQuery.getModel()).append("'");
        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getSpec()))
            querySql.append(" and spec  = '").append(mallGoodsListPageQuery.getSpec()).append("'");
        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getOrg_fullname()))
            querySql.append(" and org_fullname  = '").append(mallGoodsListPageQuery.getOrg_fullname()).append("'");
        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getSafeStock()) && mallGoodsListPageQuery.getSafeStock())
            querySql.append(" and stock  > safe_stock");
        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getSafeStock()) && !mallGoodsListPageQuery.getSafeStock())
            querySql.append(" and stock  <= safe_stock");
        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getType()))
            querySql.append(" and fictitious  = ").append(mallGoodsListPageQuery.getType());
        if(mallGoodsListPageQuery.isMall_goods_type())
            querySql.append(" and mall_goods_type  = 1");
        if(!mallGoodsListPageQuery.isMall_goods_type()){
            querySql.append(" and mall_goods_type  = 0");
        }

        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getReview_status())) {
            if (0 == mallGoodsListPageQuery.getReview_status()) {
                querySql.append(" and review_status = '").append(ApproveStatusEnum.WAIT_COMMIT.getCode()).append("'");
            }


            if (1 == mallGoodsListPageQuery.getReview_status()) {
                querySql.append(" and review_status = '").append(ApproveStatusEnum.APPROVE_ING.getCode()).append("'");
                querySql.append(" and enabled = 1");
                querySql.append(" and saled = 1");
                querySql.append(" and profile_enabled = 1");
            }
            if (2 == mallGoodsListPageQuery.getReview_status()) {
                querySql.append(" and review_status in (3,4)");
                querySql.append(" and enabled = 1");
                querySql.append(" and profile_enabled = 1");
            }
        }
        if (!PmUtil.isPm())
            querySql.append(" and vendor_id  like  concat('%','").append(PmUtil.getOrgOrganization("").getId()).append("','%')");
        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getStartDate()))
            querySql.append(" and createdTime >= '").append(PmUtil.dateFormatStr(mallGoodsListPageQuery.getStartDate())).append("'");
        if (!StringUtils.isEmpty(mallGoodsListPageQuery.getEndDate()))
            querySql.append(" and createdTime <= '").append(PmUtil.dateFormatStr(mallGoodsListPageQuery.getStartDate())).append("'");
        querySql.append(" and type in (").append(GoodsTypeEnum.Mall.getCode()).append(",").append((GoodsTypeEnum.Virtual.getCode())).append(")");
        querySql.append(" order by createdTime desc");
    }

    private Boolean goodsCheck(Map<String, Object> marketGoodsBo){
        return !StringUtils.isEmpty(marketGoodsBo.get("brand"))&&
                !StringUtils.isEmpty(marketGoodsBo.get("name"))&&
                !StringUtils.isEmpty(marketGoodsBo.get("model"))&&
                !StringUtils.isEmpty(marketGoodsBo.get("catalog_id"))&&
                !StringUtils.isEmpty(marketGoodsBo.get("unit_id"))&&
                !StringUtils.isEmpty(marketGoodsBo.get("package_unit_id"))&&
                !StringUtils.isEmpty(marketGoodsBo.get("package_num"))&&
                !StringUtils.isEmpty(marketGoodsBo.get("min_order"))&&
                !StringUtils.isEmpty(marketGoodsBo.get("pretax_price"))&&
                !StringUtils.isEmpty(marketGoodsBo.get("stock"))&&
                !StringUtils.isEmpty(marketGoodsBo.get("delivery_place"))&&
                !StringUtils.isEmpty(marketGoodsBo.get("expiry"));
    }

    private void checkCallJZApi(Map<String,Object> oldData,Map<String,Object> newData){
        //校验价格是否变更
        if(oldData.containsKey("pretax_price")&&newData.containsKey("pretax_price")
                &&!(oldData.get("pretax_price")).equals(newData.get("pretax_price"))){
            BsscResp bsscResp = callJZApi(JZApiEnum.AMOUNT_UPDATE, Collections.singletonList(newData));
            log.info("校验价格变更，调用冀中Api响应：{}",bsscResp);
        }
        //校验库存是否变更
        if(oldData.containsKey("stock")&&newData.containsKey("stock")
                &&!oldData.get("stock").toString().equals(newData.get("stock").toString())){
            BsscResp bsscResp = callJZApi(JZApiEnum.INVENTORY_UPDATE, Collections.singletonList(newData));
            log.info("校验库存变更，调用冀中Api响应：{}",bsscResp);

        }
        //校验状态是否变更
        if(oldData.containsKey("review_status")&&newData.containsKey("review_status")
                &&!oldData.get("review_status").equals(newData.get("review_status"))){
            BsscResp bsscResp = callJZApi(JZApiEnum.STATUS_UPDATE, Collections.singletonList(newData));
            log.info("校验状态变更，调用冀中Api响应：{}",bsscResp);

        }
        //校验图片是否变更
        if(oldData.containsKey("images")&&newData.containsKey("images")
                &&!HashUtil.md5(JSON.toJSONString(oldData.get("images"))).equals(HashUtil.md5(JSON.toJSONString(BoUtils.copy2List(newData.get("images"), AttachmentFormat.class))))){
            BsscResp bsscResp = callJZApi(JZApiEnum.IMAGE_UPDATE, Collections.singletonList(newData));
            log.info("校验图片变更，调用冀中Api响应：{}",bsscResp);

        }
        //校验规格是否变更
        if(oldData.containsKey("spec")&&newData.containsKey("spec")
                &&!oldData.get("spec").equals(newData.get("spec"))){
            BsscResp bsscResp = callJZApi(JZApiEnum.IMAGE_UPDATE, Collections.singletonList(newData));
            log.info("校验规格变更，调用冀中Api响应：{}",bsscResp);
        }
        //校验详情是否变更
        oldData.keySet().removeIf(key -> StringUtils.isEmpty(oldData.get(key)));
        newData.keySet().removeIf(key -> StringUtils.isEmpty(newData.get(key)));
        if(Sets.newHashSet(BoUtils.Map2Bo(oldData,GoodsDetailDto.class),BoUtils.Map2Bo(newData ,GoodsDetailDto.class)).size()!=1){
            BsscResp bsscResp = callJZApi(JZApiEnum.IMAGE_UPDATE, Collections.singletonList(newData));
            log.info("校验详情变更，调用冀中Api响应：{}",bsscResp);
        }

    }

    //TODO 对接冀中商城api
    private BsscResp callJZApi(JZApiEnum jzApiEnum, List<Map<String,Object>> goods){
        handleField(goods);
        List<GoodsModel> goodsModelList = BoUtils.copy2List(goods, GoodsModel.class);
        if(jzApiEnum.equals(JZApiEnum.IMPORT_UPDATE)){
            return punchoutBosiUtils.goodsImport(goodsModelList);
        }
        if(jzApiEnum.equals(JZApiEnum.AMOUNT_UPDATE)){
            return punchoutBosiUtils.updateGoodsAmount(CollectionUtils.firstElement(goodsModelList));
        }
        if(jzApiEnum.equals(JZApiEnum.INVENTORY_UPDATE)){
            return punchoutBosiUtils.updateGoodsInventory(CollectionUtils.firstElement(goodsModelList));
        }
        if(jzApiEnum.equals(JZApiEnum.STATUS_UPDATE)){
            return punchoutBosiUtils.updateGoodsStatus(goodsModelList);
        }
        if(jzApiEnum.equals(JZApiEnum.IMAGE_UPDATE)){
            return punchoutBosiUtils.updateGoodsImages(CollectionUtils.firstElement(goodsModelList));
        }
        if(jzApiEnum.equals(JZApiEnum.SPEC_UPDATE)){
            return punchoutBosiUtils.updateGoodsSpec(CollectionUtils.firstElement(goodsModelList));
        }
        if(jzApiEnum.equals(JZApiEnum.DETAIL_UPDATE)){
            return punchoutBosiUtils.updateGoodsDetail(CollectionUtils.firstElement(goodsModelList));
        }
        return null;
    }

    //添加商品修改记录表
    private void addGoodsHistory(String goodsId){
        try {
            BO data = BoServiceUtils.loadByBizObjectId(ApplicationConf.GOODES, goodsId).getData();
            Map<String, Object> goods = data.getData();
            if(Objects.isNull(goods)){
                log.warn("【addGoodsHistory】 query by goodsId is null :{}",goodsId);
                return;
            }
            if(StringUtils.isEmpty(RequestContext.getCorpLoginId())){
                log.warn("【addGoodsHistory】 query by corpLoginId is null");
                return;
            }
            OrgVo orgVo = PmUtil.getOrgOrganization("");
            if(Objects.isNull(orgVo)){
                log.warn("【addGoodsHistory】 query by orgVo is null");
                return;
            }
            goods.remove("createdBy");
            goods.remove("createdDept");
            goods.remove("createdTime");
            goods.remove("ownerDept");
            goods.remove("modifiedBy");
            goods.remove("modifiedTime");
            goods.remove("document");
            goods.remove("status");
            goods.put("goodses_id",goods.get("id"));
            goods.put("id", IdWorker.nextId());
            goods.put("freightRatio",orgVo.getFreight_ratio());
            BoServiceUtils.createBo(GOODS_HISTORY,goods);
        } catch (Exception e) {
            log.error("[addGoodsHistory] exception ",e);
        }
    }
}
